﻿using AutoMapper;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using YaAppoint.Common;
using YaAppoint.DapperRepositories;
using YaAppoint.Exams;
using YaAppoint.Response;

namespace YaAppoint.ExamItems
{
    /// <summary>
    /// 检查项目服务实现
    /// </summary>
    [RemoteService(isEnabled: false)]
    public class ExamItemAppService(IRepository<ExamItem, Guid> examItemRepository,
                                    ICommonAppService commonAppService,
                                    IRepository<Department, Guid> departmentRepository,
                                    IRepository<DeviceType, Guid> deviceTypeRepository,
                                    IRepository<Device, Guid> deviceRepository,
                                    IDapperExamItemRepository dapperExamItemRepository,
                                    ExamItemManager examItemManager,
                                    IConfiguration configuration,
                                    AsyncQueryableExecuter queryableExecuter,
                                    IMapper mapper) : ApplicationService, IExamItemAppService, ITransientDependency
    {


        private readonly IRepository<ExamItem, Guid> _examItemRepository = examItemRepository;
        private readonly IRepository<Department, Guid> _departmentRepository = departmentRepository;
        private readonly IRepository<DeviceType, Guid> _deviceTypeRepository = deviceTypeRepository;
        private readonly IRepository<Device, Guid> _deviceRepository = deviceRepository;
        private readonly IConfiguration _configuration = configuration;
        private readonly ExamItemManager _examItemManager = examItemManager;
        private readonly ICommonAppService _commonAppService = commonAppService;
        private readonly AsyncQueryableExecuter _queryableExecuter = queryableExecuter;
        private readonly IDapperExamItemRepository _dapperExamItemRepository = dapperExamItemRepository;
        private IMapper _mapper = mapper;

        /// <summary>
        /// 左侧边栏树Data
        /// </summary>
        public async Task<BackJson> GetLeftTreeData(Guid? depId)
        {
            var query = await _departmentRepository.GetQueryableAsync();

            if (depId != null)
            {
                query = query.Where(x => x.Id == depId);
            }
            var list = await _queryableExecuter.ToListAsync(query);
            var data = new
            {
                name = _configuration["InstitutionName"],
                id = 1,
                icon = "fa fa-hospital",
                children = list.Select(x => new // 科室
                {
                    name = x.Name,
                    id = x.Id,
                    icon = "fa fa-building",
                    children = x.DeviceTypes!.Select(deviceType => new
                    {
                        name = deviceType.Name,
                        id = deviceType.Id,
                        icon = "fa fa-list"
                    }),
                })
            };

            var res = new List<object>();
            res.Add(data);

            return new BackJson()
            {
                code = 0,
                data = res
            };
        }

        /// <summary>
        /// 删除检查项目
        /// </summary>
        public async Task<BackJson> DeleteExamItem(Guid id)
        {
            var examItem = await _examItemRepository.FirstOrDefaultAsync(x => x.Id == id);
            await _examItemManager.DeleteAsync(id);

            return new BackJson()
            {
                code = 0,
                msg = "删除成功。"
            };
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        public async Task<BackJson> DeleteMany(List<Guid> idList)
        {
            foreach (var id in idList)
            {
                await _examItemManager.DeleteAsync(id);
            }
            return new BackJson()
            {
                code = 0,
                msg = "删除成功。"
            };
        }

        /// <summary>
        /// 获取适用性别选项
        /// </summary>
        public BackJson GetApplicableSexOptions()
        {
            var data = new List<object>();
            foreach (var val in Enum.GetValues(typeof(ApplicableSex)))
            {
                var option = new
                {
                    label = _commonAppService.GetEnumValueDescription(val),
                    value = Convert.ToInt32(val)
                };

                data.Add(option);
            }
            return new BackJson()
            {
                code = 0,
                data = data,
            };
        }

        /// <summary>
        /// 获取检查项目详情
        /// </summary>
        public async Task<BackJson> GetAsync(Guid id)
        {
            var examItem = await _examItemRepository.FirstOrDefaultAsync(x => x.Id == id);
            if (examItem == null)
            {
                throw new BusinessException(CustomErrorCodes.ExamItemNotExist);
            }
            var data = _mapper.Map<ExamItem, ExamItemDto>(examItem);
            if (examItem.ParentId != null)
            {
                var parent = await _examItemRepository.FirstOrDefaultAsync(x => x.Id == examItem.ParentId);
                if (parent != null)
                {
                    data.ParentName = parent.Name;
                }
            }

            return new BackJson()
            {
                code = 0,
                data = data
            };
        }


        /// <summary>
        /// 获取科室设备类型选项
        /// </summary>
        public async Task<BackJson> GetDepDeviceTypeOptions(Guid depId)
        {
            var department = await _departmentRepository.FirstOrDefaultAsync(x => x.Id == depId);
            if (department == null)
            {
                throw new BusinessException(CustomErrorCodes.DepartmentNotExist);
            }
            var list = department.DeviceTypes!.Select(x => new
            {
                label = x.Name,
                value = x.Id
            });

            return new BackJson()
            {
                code = 0,
                data = list
            };
        }


        /// <summary>
        /// 树形列表数据
        /// </summary>
        public async Task<BackJson> GetExamItemTreeList(Guid depId, Guid deviceTypeId, string? filterName, int page, int pageSize)
        {
            var query = await _examItemRepository.GetQueryableAsync();
            query = query.Where(x => x.DepartmentId == depId && x.DeviceTypeId == deviceTypeId && x.ParentId == null);
            if (!string.IsNullOrEmpty(filterName))
            {
                query = query.Where(x => x.Name.Contains(filterName)|| x.OuterCode!.Contains(filterName));
            }
            query = query.OrderByDescending(x => x.Order);
            int total = query.Count();
            query = query.Skip(pageSize * (page - 1)).Take(pageSize);
            var list = await _queryableExecuter.ToListAsync(query);
            var data = new List<ExamItemDto>();
            foreach (var examItem in list)
            {
                var examItemDto = await GetItemRecursiveAsync(examItem);
                data.Add(examItemDto);
            }
            return new BackJson()
            {
                code = 0,
                data = new
                {
                    total = total,
                    list = data
                }
            };
        }

        /// <summary>
        ///  递归获取
        /// </summary>
        public async Task<ExamItemDto> GetItemRecursiveAsync(ExamItem examItem)
        {
            var res = await ManualMapAsync(examItem);
            res.Children = new List<ExamItemDto>();
            if (examItem.IsDirectory)
            {
                var children = (await _examItemRepository.GetListAsync(x => x.ParentId == examItem.Id)).OrderByDescending(x => x.Order).ToList();
                foreach (var child in children)
                {
                    var childDto = await GetItemRecursiveAsync(child);
                    res.Children.Add(childDto);
                }
            }
            return res;
        }




        /// <summary>
        /// 编辑提交
        /// </summary>
        public async Task<BackJson> SubmitEdit(ExamItemDto dto)
        {
            var res = new BackJson();
            var examItem = await _examItemRepository.FirstOrDefaultAsync(x => x.Id == dto.Id);
            if (examItem == null)
            {
                throw new BusinessException(CustomErrorCodes.ExamItemNotExist);
            }
            examItem.Name = dto.Name;
            examItem.Code = dto.Code;
            examItem.OuterCode = dto.OuterCode;
            examItem.IsActive = dto.IsActive;
            examItem.Order = dto.Order;
            examItem.IsActive = dto.IsActive;
            examItem.IsDirectory = dto.IsDirectory;
            examItem.ApplicableSex = dto.ApplicableSex;
            examItem.DeviceTypeId = dto.DeviceTypeId;
            examItem.ParentId = dto.ParentId;
            examItem.Workload = dto.Workload;
            examItem.RequireInterval = dto.RequireInterval;
            examItem.StartTime = dto.StartTime;
            examItem.EndTime = dto.EndTime;
            var oldDeviceIds = examItem.Devices.Select(d => d.Id).ToList();
            if (dto.Devices != null && dto.Devices.Count > 0)
            {
                foreach (var deviceId in dto.Devices)
                {
                    if (!oldDeviceIds.Contains(deviceId))
                    {
                        var device = await _deviceRepository.FirstOrDefaultAsync(d => d.Id == deviceId);
                        if (device == null)
                        {
                            throw new BusinessException(CustomErrorCodes.DeviceNotExist);
                        }
                        examItem.Devices.Add(device);
                    }
                }

                foreach (var deviceId in oldDeviceIds)
                {
                    if (!dto.Devices.Contains(deviceId))
                    {
                        var device = examItem.Devices.FirstOrDefault(d => d.Id == deviceId);
                        if (device == null)
                        {
                            throw new BusinessException(CustomErrorCodes.DeviceNotExist);
                        }
                        examItem.Devices.Remove(device);
                    }
                }
            }
            else
            {
                examItem.Devices.RemoveAll(d => 1 == 1);
            }
            await _examItemManager.SaveEdit(examItem);
            res.code = 0;
            res.msg = "保存成功。";
            return res;
        }



        /// <summary>
        /// 同步数据
        /// </summary>
        public async Task<BackJson> SyncData(Guid depId, Guid deviceTypeId)
        {
            var dep = await _departmentRepository.FirstOrDefaultAsync(x => x.Id == depId);
            if (dep == null)
            {
                throw new BusinessException(CustomErrorCodes.DepartmentNotExist);
            }
            var deviceType = await _deviceTypeRepository.FirstOrDefaultAsync(x => x.Id == deviceTypeId);
            if (deviceType == null)
            {
                throw new BusinessException(CustomErrorCodes.DeviceTypeNotExist);
            }

            var list = await _dapperExamItemRepository.GetListAsync(dep.OuterCode!, dep.Name, deviceType.OuterCode!, deviceType.Name);
            var firstLevelList = list.Where(h => string.IsNullOrWhiteSpace(h.Parent)).ToList();
            await RecursiveCompareAndHandle(firstLevelList, list, deviceType, dep);
            return new BackJson()
            {
                code = 0,
                msg = "同步成功！"
            };
        }

        /// <summary>
        /// 递归比对，并处理每 HisExamItemDto
        /// </summary>
        /// <param name="currentLevel">当前层级</param>
        /// <param name="list">所有项目</param>
        /// <returns></returns>
        private async Task RecursiveCompareAndHandle(List<HisExamItemDto> currentLevel, List<HisExamItemDto> list, DeviceType deviceType, Department department)
        {
            foreach (var item in currentLevel)
            {
                var examItem = await _examItemRepository.FirstOrDefaultAsync(x => x.OuterCode == item.Code && x.InstitutionCode == item.InstitutionCode);
                var children = list.Where(h => h.Parent == item.Code).ToList();

                if (examItem != null)
                {
                    examItem.OuterCode = item.Code;
                    examItem.Code = item.Code;
                    examItem.Name = item.Name;
                    examItem.Fee = (float?)item.Fee;
                    examItem.IsShared = item.IsShared;
                    examItem.SharedSign = item.SharedSign;
                    examItem.SharedCode = item.SharedCode;
                    examItem.SharedName = item.SharedName;
                    if (children.Count > 0)
                    {
                        examItem.IsDirectory = true;
                        await RecursiveCompareAndHandle(children, list, deviceType, department);
                    }
                    if (list.Where(x => x.Parent == item.Code).ToList().Count > 0) // 是否有子项
                    {
                        examItem.IsDirectory = true;
                    }
                    if (!string.IsNullOrEmpty(item.Parent))
                    {
                        var parent = await _examItemRepository.FirstOrDefaultAsync(x => x.OuterCode == item.Parent);
                        examItem.ParentId = parent!.Id;
                    }
                    else
                    {
                        examItem.ParentId = null;
                    }
                    await _examItemRepository.UpdateAsync(examItem);
                }
                else
                {
                    examItem = new ExamItem();
                    examItem.Name = item.Name;
                    examItem.Code = item.Code;
                    examItem.OuterCode = item.Code;
                    examItem.InstitutionCode = item.InstitutionCode;
                    examItem.InstitutionName = item.InstitutionName;
                    examItem.IsActive = true;
                    examItem.Icon = "fa fa-list";
                    examItem.Order = 0;
                    examItem.Workload = 1;
                    if (children.Count > 0)
                    {
                        examItem.IsDirectory = true;
                        examItem.Icon = "fa fa-folder";
                        await RecursiveCompareAndHandle(children, list, deviceType, department);
                    }
                    if (list.Where(x => x.Parent == item.Code).ToList().Count > 0) // 是否有子项
                    {
                        examItem.IsDirectory = true;
                    }
                    examItem.Department = department;
                    examItem.DepartmentId = department.Id;
                    examItem.DeviceType = deviceType;
                    examItem.DeviceTypeId = deviceType.Id;
                    if (!string.IsNullOrEmpty(item.Parent))
                    {
                        var parent = await _examItemRepository.FirstOrDefaultAsync(x => x.OuterCode == item.Parent);
                        examItem.ParentId = parent!.Id;
                    }
                    else
                    {
                        examItem.ParentId = null;
                    }
                    examItem.Fee = (float?)item.Fee;
                    examItem.IsShared = item.IsShared;
                    examItem.SharedSign = item.SharedSign;
                    examItem.SharedCode = item.SharedCode;
                    examItem.SharedName = item.SharedName;
                    await _examItemRepository.InsertAsync(examItem);
                }

            }
        }



        /// <summary>
        /// 提交新建
        /// </summary>
        public async Task<BackJson> SubmitCreate(CreateExamItemDto dto, Guid depId, Guid deviceTypeId)
        {
            var examItem = _mapper.Map<CreateExamItemDto, ExamItem>(dto);
            examItem.DepartmentId = depId;
            examItem.DeviceTypeId = deviceTypeId;
            examItem.Devices = new List<Device>();
            foreach (var deviceId in dto.Devices)
            {
                var device = await _deviceRepository.FirstOrDefaultAsync(d => d.Id == deviceId);
                if (device == null)
                {
                    throw new BusinessException(CustomErrorCodes.DeviceNotExist);
                }
                examItem.Devices.Add(device);
            }
            await _examItemManager.CreateAsync(examItem);
            return new BackJson()
            {
                code = 0,
                msg = "保存成功。"
            };
        }


        /// <summary>
        /// 获取文件夹树
        /// </summary>
        public async Task<BackJson> GetDirTree(Guid depId, Guid deviceTypeId, int page, int pageSize)
        {
            var query = await _examItemRepository.GetQueryableAsync();
            query = query.Where(x => x.DepartmentId == depId && x.DeviceTypeId == deviceTypeId && x.IsDirectory && x.ParentId == null)
                .OrderByDescending(x => x.Order).Skip(pageSize * (page - 1)).Take(pageSize);
            var list = await _queryableExecuter.ToListAsync(query);
            List<ExamItemDto> data = new List<ExamItemDto>();
            foreach (var examItem in list)
            {
                data.Add(await GetDirRecursiveAsync(examItem));
            }

            return new BackJson()
            {
                code = 0,
                data = new
                {
                    total = data.Count,
                    list = data.Select(x => new
                    {
                        id = x.Id,
                        name = x.Name,
                        children = x.Children,
                        icon = "fa fa-folder"
                    })
                }
            };
        }

        /// <summary>
        /// 递归映射文件夹
        /// </summary>
        public async Task<ExamItemDto> GetDirRecursiveAsync(ExamItem examItem)
        {
            var res = await ManualMapAsync(examItem);
            res.Children = new List<ExamItemDto>();
            var dirChildren = await _examItemRepository.GetListAsync(x => x.ParentId == examItem.Id && x.IsDirectory);
            if (dirChildren.Count > 0)
            {
                foreach (var child in dirChildren)
                {
                    var childDto = await GetDirRecursiveAsync(child);
                    res.Children.Add(childDto);
                }
            }
            return res;
        }

        /// <summary>
        /// 手动映射
        /// </summary>
        public async Task<ExamItemDto> ManualMapAsync(ExamItem examItem)
        {
            var dto = new ExamItemDto();
            dto.Id = examItem.Id;
            dto.Name = examItem.Name;
            dto.Code = examItem.Code;
            dto.Icon = examItem.Icon;
            dto.OuterCode = examItem.OuterCode!;
            dto.IsActive = examItem.IsActive;
            dto.Order = examItem.Order;
            dto.IsDirectory = examItem.IsDirectory;
            dto.ApplicableSex = examItem.ApplicableSex;
            dto.DeviceTypeId = examItem.DeviceTypeId;
            dto.DeviceTypeName = examItem.DeviceType.Name;
            dto.ParentId = examItem.ParentId;
            dto.Workload = examItem.Workload;
            if (examItem.ParentId != null)
            {
                var parent = await _examItemRepository.FirstOrDefaultAsync(x => x.Id == dto.ParentId);
                if (parent != null)
                {
                    dto.ParentName = parent!.Name;
                }
            }
            return dto;
        }

        /// <summary>
        /// 获取检查项目的设备选项
        /// </summary>
        public async Task<BackJson> GetDeviceOptions(Guid examItemId)
        {
            var examItem = await _examItemRepository.FirstOrDefaultAsync(item => item.Id == examItemId);
            if (examItem == null)
            {
                throw new BusinessException(CustomErrorCodes.ExamItemNotExist);
            }
            var devices = await _deviceRepository.GetListAsync(d => d.DeviceTypeId == examItem.DeviceTypeId && d.IsActive);

            return new BackJson()
            {
                code = 0,
                data = devices.Select(d => new
                {
                    label = d.Name,
                    value = d.Id
                })
            };
        }

        /// <summary>
        /// 获取设备类型下检查设备
        /// </summary>
        public async Task<BackJson> GetDeviceOptionsByDeviceType(Guid deviceTypeId)
        {
            var devices = await _deviceRepository.GetListAsync(d=>d.DeviceTypeId==deviceTypeId && d.IsActive);
            return new BackJson()
            {
                code = 0,
                data = devices.Select(d => new
                {
                    label = d.Name,
                    value = d.Id
                })
            };
        }
    }
}
